using BuildingBasicDomain;
using CommonTypes;
using System.Collections;
using System.Collections.Generic;
using System;
using CommonTypes.Math;
using CommonTypes.Math.Geometry3D;
using MVCFramework;


namespace BuildingStructuralElements
{
    [SnapContainmet]
    [ModelContainment (true)]
    [Serializable]
    public class StructuralArea : GeneralPlate , IArea ,IContainer <Node> 
    {
        public StructuralArea(IArea _area)
        {
            this._area = ConvertPoints(_area);
            this.SelectionColor = System.Drawing.Color.LightSlateGray;

            this.T = 100;
         //   (this.Polygon as MVCFramework.IDomainCollection).OnExternalyChanged +=  new EventHandler<EventArgs>(InternalNodes_OnExternalyHaveChanged);
        }

        private StructuralArea() { }
        private IArea ConvertPoints(IArea _area)
        {
            BuildingBasicDomain.Area newArea = new Area();

            foreach (IPoint point in _area.Polygon )
            {
                if (point is Node)
                    newArea.Add(point);
                else if (point is IPoint)
                    newArea.Add(Node.CreateNode(point));
            }
            return newArea;
        }

        protected override ArrayList OuterPoints
        {
            get
            {
                return (ArrayList)Area.Polygon;
            }
            set
            {
                base.OuterPoints = value;
            }
        }
        private IList<Edge> edges = new DomainCollection<Edge>(true);



        [ModelContainment]
        [SnapContainmet]
        [System.ComponentModel.Browsable(false)]
        public IList<Edge> Edges   // MOVE edges to area .
        {
            get
            {
                if (edges.Count == 0 && Polygon.Count != 0)
                    DefineEdges();
                return edges;
            }
        }

        # region " private data decleration "

        private IArea _area;

        [ModelContainment]
        [System.ComponentModel.Browsable(false)]
        public Polygon Polygon
        {
            get
            {
                return Area.Polygon;
            }

            set
            {
                this.Area.Polygon = value;
            }
        }
        [System.ComponentModel.Browsable(false)]
        public Node this[int i]
        {
            get { return Area[i] as Node; }
            set
            {
                if (value is Node)
                {
                    Area[i] = value;
                    return;
                }
                if (value is IPoint)
                {
                    try
                    {
                        Node node = (Node)value;
                        if (node != null)
                            Area[i] = node;
                    }
                    catch (Exception exp) { throw exp; }

                }
                throw new Exception("only nodes can be added to slab1 perimeter . Cast first to Node");
            }
        }
        [System .ComponentModel .Browsable (false)]
        public Area Area
        {
            set
            {
                _area = value;
            }
            get
            {
                if (_area == null)
                  _area = new Area();
                   return _area as Area ;
            }
        }

        public Vector3F normal
        {
            get
            {
                // TODO
                return _area.normal;
            }
            set
            {
                // TODO
            }
        }

        public float Constant
        {
            get
            {
                return _area.Constant;
            }

            set
            {
                throw new NotImplementedException("set constant not implemnted ");
            }
        }

        #endregion

        # region " IPnane Implementation "
        /// <summary>
        /// Method containsLine
        /// </summary>
        /// <returns>A bool</returns>
        /// <param name="beamelement2">An ILine</param>
        public bool containsLine(ILine line)
        {
            // TODO: Implement this method
            return Area.containsLine(line);
        }

        /// <summary>
        /// Method isParallel
        /// </summary>
        /// <returns>A bool</returns>
        /// <param name="beamelement2">An ILine</param>
        public bool isParallel(ILine line)
        {
            // TODO: Implement this method
            return Area.isParallel(line);
        }

        /// <summary>
        /// Method IntersectsPlane
        /// </summary>
        /// <returns>An IPoint</returns>
        /// <param name="beamelement2">An ILine</param>
        public IPoint intersectsPlane(ILine line)
        {
            // TODO: Implement this method
            return Area .intersectsPlane (line);
        }

        /// <summary>
        /// Method DistancePoint
        /// </summary>
        /// <returns>A double</returns>
        /// <param name="point">An IPoint</param>
        public double distancePoint(IPoint point)
        {
            // TODO: Implement this method
            return Area.distancePoint(point);
        }

        /// <summary>
        /// Method distanceLine
        /// </summary>
        /// <returns>A double</returns>
        /// <param name="beamelement2">An ILine</param>
        public double distanceLine(ILine line)
        {
            return Area.distanceLine(line);
        }

        /// <summary>
        /// Method projectedLine
        /// </summary>
        /// <returns>An ILine</returns>
        /// <param name="beamelement2">An ILine</param>
        public ILine projectedLine(ILine line)
        {
            // TODO: Implement this method
            return Area.projectedLine(line);
        }

        /// <summary>
        /// Method projectedPoint
        /// </summary>
        /// <returns>An IPoint</returns>
        /// <param name="point">An IPoint</param>
        public IPoint projectedPoint(IPoint point)
        {
            // TODO: Implement this method
            return Area.projectedPoint(point);
        }


        # endregion

        # region  "IContainer Implementation "

        /// <summary>
        /// Method Add
        /// </summary>
        /// <returns>A bool</returns>
        /// <param name="point">A  T</param>
        public bool Add(Node point)
        {
            if (point is Node)
            {
                Area.Add(point);

                DefineEdges();
                return true;
            }
            if (point is IPoint)
            {
                try
                {
                    Node node = Node .CreateNode (point);
                    if (node != null)
                        Area.Add(node);


                    return true;
                }
                catch { throw new Exception("only nodes can be added to slab1 perimeter . Cast first to Node"); }
              
            }
              return false;
        }

        private void DefineEdges()
        {
           edges = ((PolyLine<Edge>)Polygon);
        }

        /// <summary>
        /// Method Remove
        /// </summary>
        /// <returns>A bool</returns>
        /// <param name="point">A  T</param>
        public bool Remove(Node point)
        {
            // TODO: Implement this method
            return Area .Remove (point );
        }

        /// <summary>
        /// Method Contains
        /// </summary>
        /// <returns>A bool</returns>
        /// <param name="point">A  T</param>
        public bool Contains(Node point)
        {
            // TODO: Implement this method
            return Area.Contains (point);
        }

        /// <summary>
        /// Method Count
        /// </summary>
        /// <returns>An int</returns>
        [System.ComponentModel.Browsable(false)]
        public int Count
        {
            get
            {
                return Area.Count;
            }
        }

        /// <summary>Returns an enumerator that iterates through a collection.</summary>
        /// <returns>An <see cref="T:System.Collections.IEnumerator"></see> object that can
        /// be used to iterate through the collection.</returns>
        /// <filterpriority>2</filterpriority>
        public System.Collections.IEnumerator GetEnumerator()
        {
            return Area.GetEnumerator();
        }

        # endregion

        # region " IModiafiable Implementation "
        /// <summary>
		/// Method Move
		/// </summary>
		/// <returns>A bool</returns>
		/// <param name="v">A  Vector</param>
		public override bool Move(Vector v)
		{
            Polygon.ForEach(delegate(IPoint  node)
            {
                ((Node)node).Move(v);
            }); this.needsUpdate = true;
         //   foreach (Node node in this)
          //  { node.Move(v); }
			return true ;
		}
		
		/// <summary>
		/// Method Move
		/// </summary>
		/// <returns>A bool</returns>
		/// <param name="dx">A  double</param>
		/// <param name="dy">A  double</param>
		/// <param name="dz">A  double</param>
		public override bool Move(double dx, double dy, double dz)
		{
			// TODO: Implement this method
            return false; this.needsUpdate = true;
        }

        public void RotateToPoint(IPoint point, Vector3D angles)
        {
            foreach (Node node in this)
                node.RotateToPoint(point, angles);
            this.needsUpdate = true;
        }

        public void RotateToZero(Vector3D angles)
        {
            foreach (Node node in this)
                node.RotateToZero(angles);
            this.needsUpdate = true;

        }

        public override bool IsSelected
        {
            get
            {
                return base.IsSelected;
            }
            set
            {
                base.IsSelected = value;
                foreach (Node node in this)
                    node.IsSelected = value;
            }
        }

        #endregion 

        [Obsolete("Move this to Area and do NOT Use that",false )]
        public bool IsPointInSlab(IPoint point)
        {
            if (!this.isHorizontal()) 
                throw new  NotImplementedException("Polygon Algorithm is Implemented only for Horizontal case ");

            double[] Xs = new double [this.Count];
            double[] Zs = new double [this.Count];

            for (int i = 0; i < this.Count; i++)
            {
                IPoint _point = Area.Polygon[i];
                Xs[i] = _point.X;
                Zs[i] = _point.Z;
            }

            return CommonTypes.Geometry.PointInsidePolygon(Xs ,Zs ,point.X ,point .Z );
        }

        [Obsolete ("Do NOT USE THAT",false)]
        public bool IsLineInSlab(ILine line)
        {
            if (!line.IsHorizontal())
                return false ;

            return ( IsPointInSlab (line.SNode)&& IsPointInSlab (line.ENode));
        }

        # region " General Decleration "


        List<IPoint> getPoints()
        {
            return null;
        }
        /// <summary>
        /// Method GetArea
        /// </summary>
        /// <returns>A double</returns>
        public double GetArea()
        {
            // TODO: Implement this method
            return Area.GetArea();
        }

        /// <summary>
        /// Method GetPerimeter
        /// </summary>
        /// <returns>A double</returns>
        public double GetPerimeter()
        {
            // TODO: Implement this method
            return Area.GetPerimeter();
        }


        public IPoint  GetMiddle ()
        {
            return this.Area.GetMiddle();
        }

        /// <summary>
        /// Method IsVertical
        /// </summary>
        /// <returns>A bool</returns>
        public bool isVertical()
        {
            // TODO: Implement this method
            return Area.isVertical();
        }

        /// <summary>
        /// Method IsHorizontal
        /// </summary>
        /// <returns>A bool</returns>
        public bool isHorizontal()
        {
            // TODO: Implement this method
            return Area.isHorizontal();
        }
        # endregion

        # region " operators Implemetation "
        public static bool operator ==(StructuralArea slab1, StructuralArea slab2)
        {
            object o1 = slab1;
            object o2 = slab2;

            if (o1 == null && o2 == null) return true;
            if (o1 == null) return false;
            if (o2 == null) return false;

            if (HasSameNodes(slab1 ,slab2) )
                return true;
            else
                return false;

        }
        private static bool HasSameNodes(StructuralArea slab1, StructuralArea slab2)
        {
            bool control = true ;
            foreach (Node node in slab1.Area)
            {
                if (!slab2.Area.Contains(node))
                    control = false ;
            }
            return control;
        }

        public static bool operator !=(StructuralArea slab1, StructuralArea slab2)
        {
            return !(slab1 == slab2);
        }

        public override bool Equals(object obj)
        {
            if (obj is StructuralArea)
                return (bool)(this == (StructuralArea)obj);
            else return false;
        }
        #endregion

        [System.ComponentModel.Browsable(false)]
        public override double AngleX
        {
            get
            {
                return base.AngleX;
            }
            set
            {
                this.RotateToPoint(new Point (0,0,0), new Vector3D(value, 0, 0));
                this.needsUpdate = true;
            }
        }
        [System.ComponentModel.Browsable(false)]
        public override double AngleY
        {
            get
            {
                return base.AngleY;
            }
            set
            {
                this.RotateToPoint(new Point (0,0,0), new Vector3D(0,value , 0));
                this.needsUpdate = true;
            }
        }
        [System.ComponentModel.Browsable(false)]
        public override double AngleZ
        {
            get
            {
                return base.AngleZ;
            }
            set
            {
                this.RotateToPoint(new Point (0,0,0), new Vector3D(0, 0, value));
                this.needsUpdate = true;
            }
        }
        [System .ComponentModel .Browsable (false )]
        public override double Dx
        {
            get
            {
                return base.Dx;
            }
            set
            {
                this.Move(new Vector(value, 0, 0)); this.needsUpdate = true;
            }
        }
        [System.ComponentModel.Browsable(false)]
        public override double Dy
        {
            get
            {
                return base.Dy;
            }
            set
            {
                this.Move(new Vector(0, value, 0)); this.needsUpdate = true;
            }
        }
        [System.ComponentModel.Browsable(false)]
        public override double Dz
        {
            get
            {
                return base.Dz;
            }
            set
            {
                this.Move(new Vector(0, 0, value)); this.needsUpdate = true;
            }
        }
        
        protected void InternalNodes_OnExternalyHaveChanged(object sender, EventArgs args)
        {
          //  DefineEdges();
        }

        #region IArea Members


        public bool containsPoint(IPoint point)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }

    [SnapContainmet]
    [ModelContainment(false)]
    [Serializable]
    public class Edge : NodeLine ,IModelData ,ISelectable, ICountable 
    {
        #region ISelectable Members

        private bool isSelected;

        public bool IsSelected
        {
            get
            {
                return isSelected;
            }
            set
            {
                isSelected = value;

            }
        }

        #endregion

        #region ICountable Members

        int id;

        public int Id
        {
            get
            {
                return id;

            }
            set
            {
                id = value;


            }
        }

        #endregion

    }
}
